#ifndef _SHADER_H
#define _SHADER_H

//#include <cmath>
#include <string>
#include <iostream>
#include <map>

#include <GL\glew.h>

#include "StringUtils.h"
#include "Logger.h"

#ifdef GALLIUMENGINE_DLL 
#define GALLIUMENGINE_API __declspec( dllexport )
#else
#define GALLIUMENGINE_API __declspec( dllimport )
#endif

namespace GalliumEngine
{

	enum GALLIUMENGINE_API BindType
	{
		BINDTYPE_ATTRIBUTE,
		BINDTYPE_UNIFORM
	};

	struct BindParams
	{
		std::string id;
		BindType type;

		GALLIUMENGINE_API BindParams(std::string _id, BindType _type)
		{
			id = _id;
			type = _type;
		}
	};

	class Shader
	{
	private:
		GLuint program;

		typedef std::map<std::string,GLuint> boundValues_map;
		typedef boundValues_map::iterator boundValues_map_itr;
		typedef boundValues_map::const_iterator boundValues_map_const_itr;
		typedef std::pair<std::string,GLuint> boundValues_pair;

		boundValues_map boundValues;

		std::string id;

	public:
		GALLIUMENGINE_API Shader(void);
		GALLIUMENGINE_API Shader(std::string _id);
		GALLIUMENGINE_API ~Shader(void);

		GALLIUMENGINE_API std::string getId();

		GALLIUMENGINE_API void initialize(std::string vertexShader, std::string geometryShader, std::string fragmentShader, std::vector<BindParams> params);
		GALLIUMENGINE_API void deinitialize();

		GALLIUMENGINE_API char* loadShaderFile(const char* filename);
		GALLIUMENGINE_API void loadShader(std::string shaderFile, GLenum type);
		GALLIUMENGINE_API void linkProgram();
		GALLIUMENGINE_API void bind(std::vector<BindParams> params);
		
		GALLIUMENGINE_API void begin();
		GALLIUMENGINE_API void end();

		inline const GLuint operator[](std::string id) const
		{
			boundValues_map_const_itr itr = boundValues.find(id);

			return itr->second;
		}
	};

}

#endif
